/* 
 * File:   FileServiceProxy.cpp
 * Author: nahuel
 * 
 * Created on May 24, 2013, 8:29 PM
 */

#include <sstream>
#include <string>
#include "client_FileServiceProxy.h"
#include "common_ProtocoloConstantes.h"
#include "common_Codec.h"
#include "common_TokenFactory.h"
#include "common_NumeroUtils.h"

using namespace std;
using namespace TP;
using namespace TP::Servicios;

FileServiceProxy::FileServiceProxy(const string &pUsuario, SocketAsincronico* pSocket) {
    _usuario = pUsuario;
    this->_socket = pSocket;
}

FileServiceProxy::~FileServiceProxy() {
    _socket = NULL;
}

void FileServiceProxy::DeclareFile(const uint32_t &pToken, const std::string& fileName, const uint32_t &pVersion) {
    
    /* Formato del comando:
     * 
     *  <token>(0)|<usuario>(1)|<FILE_SERVICE>(2)|<DECLARE_FILE>(3)|<file_name>(4)|<version_archivo>(5)
     */
    
    try
    {
        string mensaje = TokenFactory::AString(pToken);
        mensaje += SEPARADOR_CAMPO;
        mensaje += _usuario;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::NOMBRE_SERVICIO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::DECLARAR_ARCHIVO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += Codec::codificar(fileName);
        mensaje += SEPARADOR_CAMPO;
        mensaje += NumeroUtils::UInt32AString(pVersion);
    
        _socket->Escribir(reinterpret_cast <const uint8_t*> (mensaje.c_str()), mensaje.length());
    }
    catch (Excepcion &ex)
    {
        cerr << endl << ex.what() << endl;
    }
}

void FileServiceProxy::DeleteFile(const uint32_t &pToken, const std::string& fileName, const uint32_t &pVersion) {
    
    /* Formato del comando:
     * 
     *  <token>(0)|<usuario>(1)|<recurso>(2)|<accion>(3)|<file_name>(4)|<version_archivo>(5)
     */
    
    try
    {
        string mensaje = TokenFactory::AString(pToken);
        mensaje += SEPARADOR_CAMPO;
        mensaje += _usuario;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::NOMBRE_SERVICIO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::BORRAR_ARCHIVO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += Codec::codificar(fileName);
        mensaje += SEPARADOR_CAMPO;
        mensaje += NumeroUtils::UInt32AString(pVersion);
    
        _socket->Escribir(reinterpret_cast <const uint8_t*> (mensaje.c_str()), mensaje.length());
    }
    catch (Excepcion &ex)
    {
        cerr << endl << ex.what() << endl;
    }
}

bool FileServiceProxy::DefineFile(const uint32_t &pToken, std::string& fileName) {
    
    /* Formato del comando:
     * 
     * <token>;<nombre_usuario>;<recurso>;<accion>;<nombre_archivo>
     */
    try
    {
        string mensaje = TokenFactory::AString(pToken);
        mensaje += SEPARADOR_CAMPO;
        mensaje += _usuario;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::NOMBRE_SERVICIO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::DEFINIR_ARCHIVO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += Codec::codificar(fileName);
    
        _socket->Escribir(reinterpret_cast <const uint8_t*> (mensaje.c_str()), mensaje.length());
    }
    catch (Excepcion &ex)
    {
        cerr << endl << ex.what() << endl;
    }
}

bool FileServiceProxy::PutFileChunk(const uint32_t &pToken, const std::string &fileName, const uint32_t &pChunkNumber, const string &pHash, const uint8_t* pChunk, const size_t pChunkSize) {
    
    // <token>;<nombre_usuario>;<recurso>;<accion>;<nombre_archivo>;<hash>;<numero_chunk>;<chunk>
    
    bool valor = true;
    
    try
    {
        // Se encodea el chunk.
        string strChunk = "";
        Codec::codificar(strChunk,pChunk, pChunkSize);
        
        string mensaje = TokenFactory::AString(pToken);
        mensaje += SEPARADOR_CAMPO;
        mensaje += _usuario;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::NOMBRE_SERVICIO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::PUT_CHUNK;
        mensaje += SEPARADOR_CAMPO;
        mensaje += Codec::codificar(fileName);
        mensaje += SEPARADOR_CAMPO;
        mensaje += pHash;
        mensaje += SEPARADOR_CAMPO;
        mensaje += NumeroUtils::UInt32AString(pChunkNumber);
        mensaje += SEPARADOR_CAMPO;
        mensaje += strChunk;
        
        _socket->Escribir((uint8_t*) mensaje.c_str(), mensaje.length());
    }
    catch (Excepcion &ex)
    {
        cerr << ex.what() << endl;
        valor = false;
    }
    
    return valor;
}

void FileServiceProxy::GetRepositorio (const uint32_t &pToken){

    try
    {
        // <token>;<nombre_usuario>;<recurso>;<accion>;
        
        string mensaje = TokenFactory::AString(pToken);
        mensaje += SEPARADOR_CAMPO;
        mensaje += _usuario;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::NOMBRE_SERVICIO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::GET_REPOSITORIO;
        
        _socket->Escribir((uint8_t*) mensaje.c_str(), mensaje.length());
    }
    catch (Excepcion &ex)
    {
        cerr << endl << ex.what() << endl;
    }    
}

/* Obtiene del archivo pFileName alojado en el sevidor el chunk indicado.
 */

bool FileServiceProxy::GetFileChunk (const uint32_t &pToken, const string &pFileName, const uint32_t &pChunkNumber){

    try
    {
        /* Formato de invocacion:
         * 
         * <token>;<nombre_usuario>;<recurso>;<accion>;<nombre_archivo>,<numero_chunk>
         * 
         */
        
        string mensaje = TokenFactory::AString(pToken);
        mensaje += SEPARADOR_CAMPO;
        mensaje += _usuario;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::NOMBRE_SERVICIO;
        mensaje += SEPARADOR_CAMPO;
        mensaje += FileServiceConstants::GET_CHUNK;
        mensaje += SEPARADOR_CAMPO;
        mensaje += Codec::codificar(pFileName);
        mensaje += SEPARADOR_CAMPO;
        mensaje += NumeroUtils::UInt32AString(pChunkNumber);
        
        _socket->Escribir((uint8_t*) mensaje.c_str(), mensaje.length());
        
        return true;
    }
    catch (Excepcion &ex)
    {
        cerr << endl << ex.what() << endl;
        return false;
    }    
}
